package service

import (
	"duoke/internal/dao"
	"duoke/model"
	utils "duoke/utils/common"
	"duoke/utils/garray"
	"duoke/utils/orm"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/util/gconv"
)

var UserCarmine = new(userCarmineService)

type userCarmineService struct{}

func (s *userCarmineService) List(c *gin.Context, req *model.SearchUserCarmine) (*model.RspList, error) {
	session := orm.Db.NewSession()
	if req.UserId != 0 {
		session.Where("user_id=?", req.UserId)
	}
	if req.IsUse != 0 {
		session.Where("is_use=?", req.IsUse)
	}
	if req.Types != 0 {
		session.Where("types=?", req.Types)
	}
	if req.CarmineId != 0 {
		session.Where("carmine_id=?", req.CarmineId)
	}
	var list []model.ReqUserCarmineStr
	count, err := session.Table(TableUserCarmine).Alias("a").Cols("a.*,b.nickname,b.avatar").
		Join("left", "user as b", "a.user_id=b.id").OrderBy("updated_at desc").
		Limit(req.PageSize, req.PageSize*(req.PageNo-1)).FindAndCount(&list)
	for k, item := range list {
		if item.ExpirationDate != "" {
			list[k].ExpirationDate = gtime.NewFromStr(gconv.String(item.ExpirationDate)).Format("Y-m-d H:i:s")
		}
	}
	if err != nil {
		return nil, err
	}
	return &model.RspList{
		Total: count,
		List:  &list,
	}, nil
}

// GiveCarmine 赠送用户卡密
func (s *userCarmineService) GiveCarmine(c *gin.Context, id, number int, userId int) error {
	info, err := Carmine.Info(c, &model.ReqCarmine{Id: id})
	if err != nil {
		return err
	}
	// 判断优惠券是否允许转增
	if info.IsZz == 2 {
		return errors.New("该优惠券不允许转增")
	}
	// 判断该优惠券是否过期
	if info.IsEffective == 1 {
		after := utils.Common.TimeAfter(gconv.String(info.ExpirationDate), gtime.Now().Format("Y-m-d H:i:s"))
		if after == 2 {
			return errors.New("该优惠券已过期")
		}
	}
	// 开始赠送
	// 判断赠送卡密是由有库存
	sku := info.Generator - info.Usage
	if info.Types == 1 && sku < number {
		return errors.New("该优惠券已没有")
	}

	// 开启事务
	session := orm.Db.NewSession()
	defer session.Close()
	if err := session.Begin(); err != nil {
		return errors.New("启动事务失败")
	}
	// 如果是限定卡券
	if info.Types == 1 {
		m := model.ReqUserCarmine{
			UserId: userId,
			IsUse:  4,
		}
		if info.IsEffective == 2 {
			m.ExpirationDate = gtime.Now().AddDate(0, 0, info.ExpirationDay).
				Format("Y-m-d H:i:s")
		}
		// 数据库发放
		update, err := session.Where("carmine_id=? and state=2", id).Limit(number).Table(TableUserCarmine).Update(m)
		if update == 0 || err != nil {
			session.Rollback()
			return errors.New("修改失败")
		}
	} else {
		// 如果赠送的是固定卡券 就要生成number张卡券
		err = Carmine.GeneratedCode(c, &model.SearchUserCarmine{
			UserId:   userId,
			FromId:   id,
			Number:   number,
			Types:    2,
			SubMchId: info.SubMchId,
		})
		if err != nil {
			session.Rollback()
			return err
		}
	}
	// 卡密使用数+number
	update, err := session.Where("id=?", id).Table(TableCarmine).Incr("usage", number).Update(
		model.ReqCarmine{})
	if update == 0 || err != nil {
		session.Rollback()
		return errors.New("修改失败")
	}
	err = session.Commit()
	if err != nil {
		return err
	}
	return nil
}

// Info 详情
func (s *userCarmineService) Info(c *gin.Context, req *model.SearchUserCarmine) (*model.ReqUserCarmine,
	error) {
	g2 := g.Map{}
	if req.UserId != 0 {
		g2["user_id=?"] = req.UserId
	}
	if req.Id != 0 {
		g2["id=?"] = req.Id
	}
	if req.IsUse != 0 {
		g2["is_use=?"] = req.IsUse
	}
	var m model.ReqUserCarmine
	err := dao.UserCarmine.Ctx(c).Where(g2).Scan(&m)
	if err != nil || m.Id == 0 {
		return nil, errors.New("该卡密不存在")
	}
	if m.ExpirationDate != nil {
		m.ExpirationDate = gtime.NewFromStr(gconv.String(m.ExpirationDate)).Format("Y-m-d H:i:s")
	}
	return &m, nil
}

// Save  详情
func (s *userCarmineService) Save(c *gin.Context, req *model.ReqUserCarmine) error {
	_, err := dao.UserCarmine.Ctx(c).Save(req)
	if err != nil {
		return err
	}
	return nil
}

// WhereSave  详情
func (s *userCarmineService) WhereSave(c *gin.Context, req map[string]any, search *model.SearchUserCarmine) error {
	g := g.Map{}
	if search.IsUse != 0 {
		g["is_use=?"] = search.IsUse
	}
	if search.CarmineId != 0 {
		g["carmine_id=?"] = search.CarmineId
	}
	_, err := dao.UserCarmine.Ctx(c).Where(g).Data(req).OmitEmpty().UpdateAndGetAffected()
	if err != nil {
		return err
	}
	return nil
}

func (s *userCarmineService) Bind(c *gin.Context, req *model.ReqUserCarmine) error {
	u, err := User.GetById(c, req.UserId, "nickname,avatar,id")
	if err != nil {
		return errors.New("用户不存在")
	}
	info, err := s.Info(c, &model.SearchUserCarmine{Id: req.Id})
	if err != nil || info.Id == 0 {
		return errors.New("改卡密不存在")
	}
	if info.UserId == 0 {
		carmine, err := Carmine.Info(c, &model.ReqCarmine{Id: req.CarmineId})
		if err != nil {
			return errors.New("该卡密不存在")
		}
		carmine.Usage += 1
		err = Carmine.Save(c, carmine)
		if err != nil {
			return errors.New("该卡密不存在")
		}
	}
	info.UserId = u.Id
	info.IsUse = 4
	if info.ExpirationDay != 0 {
		info.ExpirationDate = gtime.Now().AddDate(0, 0, info.ExpirationDay).Format("Y-m-d H:i:s")
	}
	err = s.Save(c, info)
	if err != nil {
		return err
	}
	return nil
}

// ParseImport 处理文件导入
func (s *userCarmineService) ParseImport(row utils.RowData, rowNumber int) (interface{}, bool, string) {
	var carmine model.ImportUserCarmine
	carmineId := gconv.Int(row["卡密id"])
	code := gconv.String(row["卡密code"])
	isUse := gconv.String(row["是否使用"])
	if !garray.In(isUse, g.ArrayStr{"已使用", "未使用"}) {
		return nil, false, "卡密取值范围为【已使用/未使用】"
	}
	if carmineId == 0 {
		return nil, false, "卡密id必须为正数"
	}
	if code == "" {
		return nil, false, "卡密code必须为字符串"
	}
	if isUse == "已使用" {
		carmine.IsUse = 1
	} else {
		carmine.IsUse = 2
	}
	carmine.CarmineId = carmineId
	carmine.Code = code
	return carmine, true, ""
}

// ProcessProduct 处理产品数据
func (s *userCarmineService) ProcessProduct(c *gin.Context, data interface{}) error {
	carmine, ok := data.(model.ImportUserCarmine)
	if !ok {
		return fmt.Errorf("数据类型不正确，期望Product")
	}
	info, err := Carmine.Info(c, &model.ReqCarmine{Id: carmine.CarmineId})
	if err != nil {
		return err
	}
	if info.Id == 0 {
		return errors.New("获取失败")
	}
	err = s.Save(c, &model.ReqUserCarmine{
		CarmineId:      carmine.CarmineId,
		IsUse:          carmine.IsUse,
		Title:          info.Title,
		Tag:            info.Tag,
		IsEffective:    info.IsEffective,
		ExpirationDate: info.ExpirationDate,
		ExpirationDay:  info.ExpirationDay,
		Cover:          info.Cover,
		Code:           carmine.Code,
		SubMchId:       info.SubMchId,
		Acid:           info.Acid,
		Types:          info.Types,
	})
	if err != nil {
		return err
	}
	info.Generator += 1
	if carmine.IsUse == 1 {
		info.Usage += 1
	}
	err = Carmine.Save(c, info)
	return err
}
